package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author taohongrun
 * @since 2025-02-03
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {
    private final ILearningLessonService learningLessonService;
    private final CourseClient courseClient;
    private final RedisTemplate redisTemplate;
    private final RabbitTemplate rabbitTemplate;
    private final static String RECORD_KEY_TEMPLATE = "learning:record:{}";
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        LearningLessonDTO learningLessonDTO = new LearningLessonDTO();
        Long user = UserContext.getUser();
        if (user == null) throw  new BadRequestException("用户未登录");

        LearningLesson learningLesson = learningLessonService.lambdaQuery().eq(LearningLesson::getCourseId, courseId).eq(LearningLesson::getUserId, user).one();
        if (learningLesson == null) throw new BadRequestException("该用户未拥有该课程");

        learningLessonDTO.setId(learningLesson.getId());
        List<LearningRecord> recordList = lambdaQuery().eq(LearningRecord::getLessonId, learningLesson.getId()).list();
        learningLessonDTO.setLatestSectionId(learningLesson.getLatestSectionId());
        learningLessonDTO.setRecords(BeanUtil.copyToList(recordList, LearningRecordDTO.class));
        return learningLessonDTO;
    }

    @Override
    public void addLearningRecord(LearningRecordFormDTO recordDTO) {
        Long user = UserContext.getUser();
        if (user==null) throw new BadRequestException("用户未登录");

        log.info("添加学习记录........");
        if(recordDTO.getSectionType()==SectionType.EXAM){
            handleExamRecord(recordDTO,user);
        }else {
            log.info("recordDto:{}",recordDTO);
            handleVideoRecord(user,recordDTO);
        }

    }
    private void handleExamRecord(LearningRecordFormDTO recordDTO, Long userId){
        LearningRecord record = new LearningRecord();
        BeanUtils.copyProperties(recordDTO,record);
        record.setUserId(userId);
        record.setFinished(true);
        record.setFinishTime(recordDTO.getCommitTime());
        save(record);

        handleLearningLessonsChanges(recordDTO);

        finishLearningLessons(recordDTO.getLessonId());
    }

    private void handleVideoRecord(Long userId, LearningRecordFormDTO recordDTO){
        LearningRecord learningRecord = lambdaQuery().eq(LearningRecord::getLessonId, recordDTO.getLessonId()).eq(LearningRecord::getSectionId, recordDTO.getSectionId()).one();
        log.info("learningRecord:{}",learningRecord);
        if (learningRecord != null){
            log.info("处理已存在记录");
            handleExitsVideoRecord(learningRecord,recordDTO);
        }else {
            log.info("处理未存在记录");
            handleNotExitsVideoRecord(userId,recordDTO);
        }
    }

    private void handleExitsVideoRecord(LearningRecord learningRecord, LearningRecordFormDTO recordDTO){
        //判断是否学完当前小节
        Boolean finished = false;
        if(recordDTO.getMoment()*2 > recordDTO.getDuration()) finished = true;


       /* //更新学习记录
        lambdaUpdate()
                .set(LearningRecord::getMoment,recordDTO.getMoment())
                .set(finished,LearningRecord::getFinished,true)
                .set(finished,LearningRecord::getFinishTime,recordDTO.getCommitTime())
                .eq(LearningRecord::getId,learningRecord.getId())
                .update();
        //更新课程表最近学习小节以及时间
        handleLearningLessonsChanges(recordDTO);*/
        //优化为存储到缓存
        RecordCacheData recordCacheData = new RecordCacheData(learningRecord.getId(), recordDTO.getMoment(), finished);
        redisTemplate.opsForHash().put(formatRecordRedisKey(recordDTO.getLessonId()),recordDTO.getSectionId().toString(),JSONUtil.toJsonStr(recordCacheData));
        //创建延时任务
        LearningRecord taskLearningRecord = new LearningRecord();
        taskLearningRecord.setLessonId(learningRecord.getLessonId());
        taskLearningRecord.setMoment(recordDTO.getMoment());
        taskLearningRecord.setSectionId(recordDTO.getSectionId());
        taskLearningRecord.setFinished(learningRecord.getFinished());
        taskLearningRecord.setCreateTime(recordDTO.getCommitTime());
        rabbitTemplate.convertAndSend(MqConstants.Exchange.LEARNING_COMMIT_DELAY,MqConstants.Key.COMMIT_DELAY_KEY,taskLearningRecord,message -> {
            message.getMessageProperties().setHeader("x-delay",20000);
            return message;
        });


    }

    private void handleNotExitsVideoRecord(Long userId, LearningRecordFormDTO recordDTO){
        LearningRecord record = new LearningRecord();
        BeanUtils.copyProperties(recordDTO,record);
        record.setUserId(userId);
        save(record);
        handleLearningLessonsChanges(recordDTO);
    }
    private void handleLearningLessonsChanges(LearningRecordFormDTO recordDTO) {
        learningLessonService
                .lambdaUpdate()
                .set(LearningLesson::getLatestLearnTime, recordDTO.getCommitTime())
                .set(LearningLesson::getLatestSectionId, recordDTO.getSectionId())
                .update();
    }

    private void finishLearningLessons(Long lessonId) {
        //1.判断是否完成lesson所有小节
        Boolean finished = false;
        LearningLesson lesson = learningLessonService.getById(lessonId);
        //课程小节数在课程表中
        CourseFullInfoDTO courseInfoById = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
        if(lesson.getLearnedSections()+1 == courseInfoById.getSectionNum()) finished=true;

        learningLessonService.lambdaUpdate()
                .setSql("learned_sections = learned_sections + 1")
                .set(finished,LearningLesson::getStatus, LessonStatus.FINISHED)
                .eq(LearningLesson::getId, lessonId)
                .update();
    }

    public void handleCommitDelayTask(LearningRecord learningRecord){
        log.info("延迟任务参数:{}",learningRecord);
        String key = formatRecordRedisKey(learningRecord.getLessonId());
        String hashKey = learningRecord.getSectionId().toString();
        Object learningRecordCache =  redisTemplate.opsForHash().get(key, hashKey);
        log.info("learningRecordCache:{}",learningRecordCache);
        String learningRecordJson = JSONUtil.toJsonStr(learningRecordCache);
        log.info("learningRecordJson:{}",learningRecordJson);
        RecordCacheData nowLearningRecord = JSONUtil.toBean(learningRecordJson, RecordCacheData.class);
        log.info("nowLearningRecord:{}",nowLearningRecord);
        Integer nowMoment = nowLearningRecord.getMoment();
        log.info("原moment:{},现moment：{}",learningRecord.getMoment(),nowMoment);
        if (!nowMoment.equals(learningRecord.getMoment())){log.info("视频还在观看，无需更新"); return;}
        log.info("视频需要进行记录");
        //判断是否初次完成
        boolean firstFinished = learningRecord.getFinished().equals(false) && nowLearningRecord.getFinished();
        //更新学习记录
        lambdaUpdate().set(LearningRecord::getMoment,nowMoment).set(firstFinished,LearningRecord::getFinished, nowLearningRecord.getFinished()).set(firstFinished,LearningRecord::getFinishTime,learningRecord.getCreateTime()).eq(LearningRecord::getId, nowLearningRecord.getId()).update();
        log.info("更新学习记录");
        //更新最近lesson最近学习小节以及时间
        learningLessonService.lambdaUpdate().eq(LearningLesson::getId,learningRecord.getLessonId()).set(LearningLesson::getLatestLearnTime, LocalDateTime.now()).set(LearningLesson::getLatestSectionId,learningRecord.getSectionId()).update();
        log.info("更新最近lesson最近学习小节以及时间");

        //根据曾经是否完成，本次是否完成 来进行完成小节后更改lesson表的操作
        if(firstFinished) {
            log.info("初次完成该小节");
            finishLearningLessons(learningRecord.getLessonId());
        }
    }

    private String formatRecordRedisKey(Long lessonId){
        return StrUtil.format(RECORD_KEY_TEMPLATE,lessonId);
    }


    @Data
    @NoArgsConstructor
    private static class RecordCacheData{
        private Long id;
        private Integer moment;
        private Boolean finished;

        public RecordCacheData(LearningRecord record) {
            this.id = record.getId();
            this.moment = record.getMoment();
            this.finished = record.getFinished();
        }

        public RecordCacheData(Long id, Integer moment, Boolean finished) {
            this.id = id;
            this.moment = moment;
            this.finished = finished;
        }
    }

}
